#include <iterator>
#include "MarkupSTL.h"
#include "global.h"
#include "cmd.h"
#include "Game.h"
#include "RedisClient.h"
#include "Logic.h"
#include "json.h"
#include "Host.h"
#include <limits>
#include "NodeServer.h"
#include "1650_agentbackend.pb.h"
#include "1000_user_wallet.pb.h"

// http server
#include "handler.h"
#include "http.h"
#include "buffer.h"
#include "listener.h"
#include "mainworker.h"
#include "context.h"

static CGameServer* g_pGame = NULL;

CGameServer::CGameServer():m_cliPhp(NULL)
{
	m_httpListenPort = 10086;
}

CGameServer::~CGameServer()
{
}

bool CGameServer::InitGame()
{
	const char* szconfig = TGlobal::_xmlconfig.c_str();
	ReadCommonConf(szconfig);

    // 使用全局指针处理业务
    g_pGame = this;

	// httpserver
	g_Ctx.host = m_pHost;

	if (!g_Ctx.msg_router.Init(m_httpListenPort))
	{
		log_error("g_Ctx.msg_router Init failed");
		return false;
	}
   
	return true;
}

int CGameServer::OnBYTimeOut(int Timerid)
{
	return 0;
}

int CGameServer::ProcessPacket(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	if (SERVER_TYPE_PHP == pHandler->getType())
		ProPHPPack(pHandler, inputPkg);
	else if (CONN_TYPE_CONN == pHandler->getConnType())
		ProcSrvPack(pHandler, inputPkg);
	else
		log_error("invalid pack,conn typd,%d,src type,%d", pHandler->getConnType(), inputPkg->GetSrcType());

	return 0;
}

int CGameServer::ProPHPPack(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	unsigned int cmd = inputPkg->GetCmdType();
	if (AGENT_BACKEND_HEART_BEAT == cmd)
	{
		ProcHeartBeat(pHandler, inputPkg);
		return 0;
	}

	unsigned int dstSrvType = inputPkg->GetDstType();
	sendToSrv(pHandler, inputPkg);

	return 0;
}
int CGameServer::HandleRefreshConfig(SocketHandler* pHandler, NETInputPacket* inputPkg){

	unsigned short dsttype = inputPkg->GetDstType();
	unsigned int dstsid = inputPkg->GetDstSvid();

	if (dsttype > 0 && dstsid > 0)
	{
		m_pHost->SendPacket(inputPkg, dsttype, dstsid);
	}
	else if (inputPkg->GetDstType() > 0)
	{
		m_pHost->BroadcastMessageDirect(inputPkg, dsttype);
	}
	else
		log_error("wrong root,dsttype,%d,dstsid,%d", dsttype, dstsid);


    return 0;
}
int CGameServer::HandleVerifyRank(SocketHandler* pHandler, NETInputPacket* inputPkg){
//    agentbackend::RequestVerifyRank request;
//    bool bRet = inputPkg->parsePb(&request);
//    log_debug("HandleVerifyRank bRet=%d reward_id=%d uid=%d audit_uid=%d audit_time=%d audit_name=%s",
//        bRet, request.reward_id(), request.uid(), request.audit_uid(), request.audit_time(), request.audit_name().c_str());

    return 0;
}
int CGameServer::ProcSrvPack(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	unsigned int cmd = inputPkg->GetCmdType();
	unsigned short stype = pHandler->getType();

	unsigned int uid = 0;
	if (cmd == client_proto::UWSMI_PHP_CREATE_ORDER_REQ)
	{
		client_proto::PhpChargeOrderReq msg;
		inputPkg->parsePb(&msg);
		uid = msg.uid();
	}

	log_debug("send to php,srctype,%d, dst type,%u, cmd,%u, dst id,%u,uid,%u", stype, inputPkg->GetDstType(), cmd, inputPkg->GetDstSvid(), uid);
	// TODO 2024 06 22 更改发送给PHP的消息
    // if(cmd == client_proto::UWSMI_PHP_CREATE_ORDER_REQ || cmd == client_proto::UWSMI_PHP_CREATE_ORDER_RESP ||
    // cmd == client_proto::UWSMI_PHP_COMPLETE_ORDER_REQ || cmd == client_proto::UWSMI_PHP_COMPLETE_ORDER_RESP){
        uint32 callbackID = 0;
        std::string& url = m_phpPostUrl; //"http://192.168.2.60:8785/charge/serverTcpTransfer";
        std::string body = std::string(inputPkg->packet_buf(), inputPkg->packet_size());
        std::map<std::string, std::string> headers;
        headers["Content-Type"] = "text/plain";
        HiveNS::MainWorker::getInstance()->sendHttpPOST(url, body, headers, callbackID);

        log_debug("sendHttpPOST url=%s callbackID=%u", url.c_str(), callbackID);
    // }else{
    //     sendToPHP(pHandler, inputPkg);
    // }

	return 0;
}

int CGameServer::sendToSrv(SocketHandler* pHandler, NETInputPacket* pack)
{
	unsigned short dsttype = pack->GetDstType();
	unsigned int dstid = pack->GetDstSvid();
	unsigned int uid = pack->GetSrcSvid();//uid->srcsid 

	log_debug("send to srv,srctype,%d, dst type,%d, cmd,%d, dstid,%d, srcid,%d", pHandler->getType(), dsttype, pack->GetCmdType(), dstid, uid);
    if (dsttype > 0)
	{
		if (uid > 0)
		{
			m_pHost->SendtoSrv(pack, dsttype, uid);//mod
		}
		else
		{
			if (0 == dstid)
			{
				m_pHost->BroadcastMessageDirect(pack, dsttype);//broadcast
			}
			else
			{
				m_pHost->SendPacket(pack, dsttype, dstid);//to one indeed server
			}
		}


	}

	return 0;
}
int CGameServer::SendToSrvNew(NETInputPacket* pack){
	unsigned short dsttype = pack->GetDstType();
	unsigned int dstid = pack->GetDstSvid();
	unsigned int uid = pack->GetSrcSvid();//uid->srcsid

	log_debug("send to srv, dst type,%d, cmd,%d, dstid,%d, srcid,%d", dsttype, pack->GetCmdType(), dstid, uid);
    if (dsttype > 0)
	{
		// todo 是否可调整为走dispatch转发，无需在master加配置
		if (uid > 0)
		{
			m_pHost->SendtoSrv(pack, dsttype, uid);//mod
		}
		else
		{
			if (0 == dstid)
			{
				m_pHost->BroadcastMessageDirect(pack, dsttype);//broadcast
			}
			else
			{
				m_pHost->SendPacket(pack, dsttype, dstid);//to one indeed server
			}
		}


	}
    return 0;
}

int CGameServer::sendToOneSrv(unsigned short stype, unsigned int sid, NETInputPacket* pack)
{
	map<unsigned short, map<unsigned int, CClient*> >::iterator itor = m_node.find(stype);
	if (m_node.end() != itor)
	{
		map<unsigned int, CClient*>::iterator itor1 = itor->second.find(sid);
		if (itor->second.end() != itor1)
		{
			itor1->second->Send(pack);
		}
	}
	return 0;
}

int CGameServer::srvtypeModSend(unsigned short stype, unsigned int mod, CCPacketBase* pack)
{
	map<unsigned short, map<unsigned int, CClient*> >::iterator itor = m_node.find(stype);
	map<unsigned short, vector<unsigned int> >::iterator vitor = m_nodeId.find(stype);
	if (m_node.end() != itor && m_nodeId.end() != vitor && vitor->second.size() > 0)
	{
		assert(itor->second.size() == vitor->second.size());
		int index = mod % vitor->second.size();
		unsigned int sid = vitor->second[index];
		map<unsigned int, CClient*>::iterator itor1 = itor->second.find(sid);
		if (itor->second.end() != itor1)
		{
			itor1->second->Send(pack);
			//log_debug("srv %d, type %d", sid, stype);
		}
		else
		{
			log_debug("find no srv %d", sid);
		}
	}
	else
	{
		log_debug("find no srv type %d", stype);
	}
	return 0;
}

int CGameServer::srvtypeRandSend(unsigned short stype, NETInputPacket* pack)
{
	static unsigned int randindex = 0;

	map<unsigned short, map<unsigned int, CClient*> >::iterator itor = m_node.find(stype);
	map<unsigned short, vector<unsigned int> >::iterator vitor = m_nodeId.find(stype);
	if (m_node.end() != itor && m_nodeId.end() != vitor && vitor->second.size() > 0)
	{
		assert(itor->second.size() == vitor->second.size());
		randindex = ++randindex % numeric_limits<unsigned int>::max();
		int index = randindex % vitor->second.size();
		unsigned int sid = vitor->second[index];
		map<unsigned int, CClient*>::iterator itor1 = itor->second.find(sid);
		if (itor->second.end() != itor1)
		{
			itor1->second->Send(pack);
			log_debug("srv %d, type %d", sid, stype);
		}
		else
		{
			log_debug("find no srv %d", sid);
		}
	}
	else
	{
		log_debug("find no srv type %d", stype);
	}

	return 0;
}

int CGameServer::sendToPHP(SocketHandler* pHandler, NETInputPacket* pack)
{
	if (!m_cliPhp)
		return -1;

	m_cliPhp->Send(pack);


// 	unsigned int handlerflow = pack->GetDstSvid();
// 	if (handlerflow > 0)
// 	{
// 		map<unsigned int, CClientHandler*>::iterator itor = m_pHost->m_pNode->m_handlerList.find(handlerflow);
// 		if (m_pHost->m_pNode->m_handlerList.end() != itor && !itor->second->_isDel)
// 		{
// 			itor->second->Send(pack);
// 
// 			log_debug("find handler,flow,%d,cmd,%d,from,%d", handlerflow, pack->GetCmdType(), pHandler->getType());
// 			return 0;
// 		}
// 		{
// 			log_debug("find no client handler,flow,%d,cmd,%d,from,%d", handlerflow, pack->GetCmdType(), pHandler->getType());
// 		}
// 	}
// 
// 	for (map<unsigned int, CClientHandler*>::reverse_iterator itor = m_pHost->m_pNode->m_handlerList.rbegin(); m_pHost->m_pNode->m_handlerList.rend() != itor; ++itor)
// 	{
// 		if (!itor->second->_isDel)
// 		{
// 			itor->second->Send(pack);
// 			log_debug("rand handler,flow,%d,cmd,%d,from,%d", handlerflow, pack->GetCmdType(), pHandler->getType());
// 
// 			break;
// 		}
// 		else
// 		{
// 			log_debug("handler off,flow,%d,cmd,%d,from,%d", itor->second->m_HandlerID, pack->GetCmdType(), pHandler->getType());
// 		}
// 	}

	return 0;
}

int CGameServer::ProcEventBackConn(int ev_id, SpiderEvent* pEvent)
{
	if(pEvent && pEvent->evParam.ptr)
	{
		CClient* client = (CClient*)pEvent->evParam.ptr;
		unsigned short stype =  client->getType();
		unsigned int sid = client->getId();
		map<unsigned short, map<unsigned int, CClient*> >::iterator itor = m_node.find(stype);
		if (m_node.end() != itor)
		{
			itor->second[sid] = client;
		}
		else
		{
			m_node.insert(make_pair(stype, map<unsigned int, CClient*>()));
			m_node[stype].insert(make_pair(sid, client));
		}
		
		map<unsigned short, vector<unsigned int> >::iterator vitor = m_nodeId.find(stype);
		if(m_nodeId.end() != vitor)
		{
			vector<unsigned int>::iterator vitor1 = ::find(vitor->second.begin(), vitor->second.end(), sid);
			if (vitor->second.end() == vitor1)
			{
				vitor->second.push_back(sid);
				::sort(vitor->second.begin(), vitor->second.end());
			}
			
		}
		else
		{
			m_nodeId.insert(make_pair(stype, vector<unsigned int>()));
			m_nodeId[stype].push_back(sid);
		}
	}
	
	return 0;
}

int CGameServer::ProcEventBackClose(int ev_id, SpiderEvent* pEvent)
{
	if(pEvent && pEvent->evParam.ptr)
	{
		CClient* client = (CClient*)pEvent->evParam.ptr;
		unsigned short stype = client->getType();
		unsigned int sid = client->getId();
		map<unsigned short, map<unsigned int, CClient*> >::iterator itor = m_node.find(stype);
		if (m_node.end() != itor)
		{
			map<unsigned int, CClient*>::iterator itor1 = itor->second.find(sid);
			if (itor->second.end() != itor1)
				itor->second.erase(itor1);
		}

		map<unsigned short, vector<unsigned int> >::iterator vitor = m_nodeId.find(stype);
		if (m_nodeId.end() != vitor)
		{
			vector<unsigned int>::iterator vitor1 = ::find(vitor->second.begin(), vitor->second.end(), sid);
			if (vitor->second.end() != vitor1)
				vitor->second.erase(vitor1);
		}
	}
}

int CGameServer::ProcEventClientClose(int ev_id, SpiderEvent* pEvent)
{
	if (pEvent && pEvent->evParam.ptr)
	{
		CClientHandler* handler = (CClientHandler*)pEvent->evParam.ptr;
		unsigned int flow = handler->m_HandlerID;

		log_debug("php tcp off %d", flow);
	}
}

int CGameServer::ProcGameInit(int ev_id, SpiderEvent* pEvent)
{
	if (m_phpCfg.port > 0 && strlen(m_phpCfg.ip) > 0)
	{
		if (!m_cliPhp)
		{
			m_cliPhp = new CClient(m_pHost->m_pNode);
			m_cliPhp->setId(m_phpCfg.svid);
			m_cliPhp->setType(SERVER_TYPE_PHP);
			if (0 != m_cliPhp->InitConnect(m_phpCfg.ip, m_phpCfg.port))
			{
				log_boot("php connect [%s:%d]  err", m_phpCfg.ip, m_phpCfg.port);
			}
		}
	}

	return 0;
}

void CGameServer::ProcHeartBeat(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	pHandler->Send(inputPkg);
	//
}

bool CGameServer::ReadCommonConf(const char* strxml)
{
	CMarkupSTL  markup;
	if (!markup.Load(strxml))
	{
		log_error("Load xml %s failed", strxml);
		return false;
	}

	if (!markup.FindElem("application"))
	{
		log_error("Not Found Elem [application] in xml[%s]", strxml);
		return false;
	}

	if (!markup.IntoElem())
	{
		log_error("IntoElem [application] failed.");
		return false;
	}


	if (!markup.FindElem("php"))
	{
		log_error("Not Found Elem [php] in xml[%s]", strxml);
		return false;
	}
	else
	{
		m_phpCfg.reset();
		m_phpCfg.svid = atoi(markup.GetAttrib("svid").c_str());
		strncpy(m_phpCfg.ip, markup.GetAttrib("ip").c_str(), sizeof(m_phpCfg.ip) - 1);
		m_phpCfg.port = atoi(markup.GetAttrib("port").c_str());

	}

	if (!markup.FindElem("phppost"))
	{
		log_error("Not Found Elem [php] in xml[%s]", strxml);
		return false;
	}
	else
	{
	    m_phpPostUrl = std::string(markup.GetAttrib("url").c_str());
	    m_httpListenPort = atoi(markup.GetAttrib("port").c_str());
	    log_debug("ReadCommonConf m_phpPostUrl=%s m_httpListenPort=%d", m_phpPostUrl.c_str(), m_httpListenPort);
	}

	log_debug("ReadCommonConf succ!!");

	return true;
}